package org.jiucheng.magpiebridge.client.aio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.Enumeration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import org.jiucheng.magpiebridge.client.util.ServerInfo;
import org.jiucheng.magpiebridge.protocol.Message;
import org.jiucheng.magpiebridge.transfer.aio.TransferAttachment;

/**
 * 
 * @author jiucheng
 *
 */
public class ClientAttachment {
	private ClientEstablishmentCompletionHandler clientEstablishmentCompletionHandler = new ClientEstablishmentCompletionHandler();
	private ClientReadCompletionHandler clientReadCompletionHandler = new ClientReadCompletionHandler();
	private ClientWriteCompletionHandler clientWriteCompletionHandler = new ClientWriteCompletionHandler();
	private ClientWriteNoReadCompletionHandler clientWriteNoReadCompletionHandler = new ClientWriteNoReadCompletionHandler();
	
	private ConcurrentHashMap<Integer, TransferAttachment> transferAttachments = new ConcurrentHashMap<Integer, TransferAttachment>();
    // 当前在写
    public final AtomicBoolean writed = new AtomicBoolean(false);
    
	private AsynchronousSocketChannel client;
	private ByteBuffer writeByteBuffer;
	private ByteBuffer readByteBuffer;
	private boolean failed = false;
	
	private ServerInfo serverInfo;
	
	public void setServerInfo(ServerInfo serverInfo) {
        this.serverInfo = serverInfo;
    }
	
	public ServerInfo getServerInfo() {
        return serverInfo;
    }
	
	public ClientEstablishmentCompletionHandler getClientEstablishmentCompletionHandler() {
		return clientEstablishmentCompletionHandler;
	}
	
	public ClientReadCompletionHandler getClientReadCompletionHandler() {
		return clientReadCompletionHandler;
	}
	
	public ClientWriteCompletionHandler getClientWriteCompletionHandler() {
		return clientWriteCompletionHandler;
	}
	
	public ClientWriteNoReadCompletionHandler getClientWriteNoReadCompletionHandler() {
		return clientWriteNoReadCompletionHandler;
	}
	
	public AsynchronousSocketChannel getClient() {
		return client;
	}
	
	public ClientAttachment setClient(AsynchronousSocketChannel client) {
		this.client = client;
		return this;
	}
	
	public ByteBuffer getReadByteBuffer() {
		return readByteBuffer;
	}
	
	public ClientAttachment setReadByteBuffer(ByteBuffer readByteBuffer) {
		this.readByteBuffer = readByteBuffer;
		return this;
	}
	
	public ByteBuffer getWriteByteBuffer() {
		return writeByteBuffer;
	}
	
	public ClientAttachment setWriteByteBuffer(ByteBuffer writeByteBuffer) {
		this.writeByteBuffer = writeByteBuffer;
		return this;
	}
	
	public boolean canWrited() {
        while (!writed.compareAndSet(false, true)) {
        	try {
				TimeUnit.MILLISECONDS.sleep(50L);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
        }
        return true;
	}
	
	public boolean isFailed() {
		return failed;
	}
	
	public ClientAttachment setFailed(boolean failed) {
		this.failed = failed;
		return this;
	}
	
	public ConcurrentHashMap<Integer, TransferAttachment> getTransferAttachments() {
		return transferAttachments;
	}
	
    // 代理连接断开消息发送
    public void disconnect(int uri) {
        if (canWrited()) {
            Message message = new Message();
            message.setMagic(Message.MAGIC);
            message.setType(Message.Type.DISCONNECT);
            message.setUri(uri);
            ByteBuffer writeByteBuffer = Message.toByteBuffer(message);
        	getClient().write(writeByteBuffer, setWriteByteBuffer(writeByteBuffer), getClientWriteNoReadCompletionHandler());
        }
    }
    
    // HEARTBEAT
    public void heartbeat() {
		if (canWrited()) {
            Message message = new Message();
            message.setMagic(Message.MAGIC);
            message.setType(Message.Type.HEARTBEAT);
            ByteBuffer writeByteBuffer = Message.toByteBuffer(message);
            getClient().write(writeByteBuffer, setWriteByteBuffer(writeByteBuffer), getClientWriteNoReadCompletionHandler());
		}
    }
    
    public void close () {
        try {
			getClient().close();
		} catch (IOException e) {
		}
		ConcurrentHashMap<Integer, TransferAttachment> tas = getTransferAttachments();
		Enumeration<Integer> uris = tas.keys();
		if (uris != null) {
			while (uris.hasMoreElements()) {
				Integer uri = uris.nextElement();
				TransferAttachment ta = tas.remove(uri);
				if (ta != null) {
					ta.disconnect();
				}
			}
		}
    }
}
